package org.myorg.v6;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.myorg.v4.Para4;
import org.myorg.v4.RWF4;



public class Mountain6 {
	
	protected static final Log LOG = LogFactory.getLog(Mountain6.class);
	
	public Integer length = new Integer(0);
	public Integer pos = new Integer(0);

	public Long t1 = new Long(0);
	public Long itr = new Long(0);
	public Double[] data = new Double[0];
	

	public Double[] value = new Double[0];
	public Long[] it = new Long[0];
	public Long[] time = new Long[0];
	
	public void initRecord(Double[] data) {
		
		LOG.debug("initial pos is " + pos + "length is " + data.length);
		
		this.length = data.length;
		this.data = data;
		value = new Double[length];
		it = new Long[length];
		time = new Long[length];
		t1 = System.currentTimeMillis();
	}
	
	public void record(People p) {
		// TODO Auto-generated method stub
		
		LOG.debug("itr is " + itr + " pos is " + pos + " length is " + length );
		
		int best_p = p.getBest();
		double best_v = Function.caculate(p.getPeople()[best_p]);
		
		
		itr++;
		while (pos < length && best_v >= data[pos]) {
			
			LOG.info("record, pos is " + pos + "length is " + length);
			
			value[pos] = new Double(best_v);
			it[pos] = itr;
			time[pos] = System.currentTimeMillis() - t1;
			pos++;
		}
	}
	
	public boolean isCompleted() {
		// TODO Auto-generated method stub
		return (pos==length)?true:false;
	}
	
	public static void main(String args[]) {
		int ln = 25;
		
		double mit = 0;
		double mrt = 0;
		
		String value = "";
		
		String time = "";
		
		String it = "";
		
		String res = "";
		

		
		for(int ii = 0; ii < ln; ii++) {
			long st = System.currentTimeMillis();
			Mountain6 rec = ga();
			

			
			long rt = System.currentTimeMillis() - st;
			
			
			mit = mit + rec.it[rec.length - 1];
			mrt = mrt + rt;
			
			value = "";
			time = "";
			it = "";
			
			for (int i = 0; i < rec.length; i++) {
				value = value + "\t" + rec.value[i];
				time = time + "\t" + rec.time[i];
				it = it + "\t" + rec.it[i];
			}

			res = res + value + "\n" + time + "\n" + it + "\n";
			
			

			System.out.println(ii + " completed");
			
			System.out.println("sum of iterator time is "+ it);
			System.out.println("time is "+ rt);
		}
		
		RWF4.wlf(res.getBytes(), "/home/stanley/Documents/paper_assistant/graduate/data/mga0305");
		
		System.out.println("sum of iterator time is "+ mit);
		
	}
	
	public static Mountain6 ga() {
		
		Double data[] = { 0.9, 0.99, 0.999, 0.9999, 0.99999, 0.999999, 0.9999999, 0.99999999};
		
		Mountain6 rec = new Mountain6();
		//rec.initRecord(Para4.mag);
		rec.initRecord(data);
		
		
		int best_p = 0;
		long it = 0;
		double best_v = 0;
		People my_p = new People(200,63);
		Evolution my_e = new Evolution(0.1, 0.2, 0.1, my_p);
		
		for (long i=0; i < Long.MAX_VALUE; i++) {
			my_p.caculateFitness();
			my_e.select();
			my_e.crossOver();
			my_e.mutation();
			
			best_p = my_p.getBest();
			best_v = Function.caculate(my_p.getPeople()[best_p]);
			it++;
			
			rec.record(my_p);
			if (rec.isCompleted()) {
				break;
			}
			//if((1 - best_v) < 1.0E-05) {
			//	break;
			//}
			//System.out.println("the best value is "+best_v);
		}
		
	
		System.out.println("the best individual is "+my_p.getPeople()[best_p]);
		System.out.println("the best value is "+best_v);
		System.out.println("iterator time is "+ it);
		return rec;
	}
}

/*class Function {
	static public double caculate(String person) {
		double res = 0;
		*//**
		 * add your function here
		 * for example: f(x)= sin(x) x [0, 3.14] 
		 * set the genetic length is 20, so the mapping relation is
		 * [0, 2^20] -> [0, 3.14]
		 *//*
		int tem = Integer.parseInt(person, 2);
		double x = tem*3.14/(Math.pow(2, person.length()));
		res = Math.cos(x)+Math.sin(x);
		return res;
	}
	static public boolean better(double a, double b) {
		return a<b?true:false;
	}
}
*/
class Function {
/*	static public double caculate(String person) {
		double res = 0;
		*//**
		 * add your function here
		 * for example: f(x)= sin(x) x [0, 3.14] 
		 * set the genetic length is 20, so the mapping relation is
		 * [0, 2^20] -> [0, 3.14]
		 *//*
		int tem = Integer.parseInt(person, 2);
		//double x = tem*3.14/(Math.pow(2, person.length()));
		//res = Math.cos(x)+Math.sin(x);
		double N = Math.pow(2, person.length()) -1;
		if (tem != 0)
			res = (N - (double)tem)/(N-1);
		else
			res = -1;
		return res;
	}*/
	
	static public double caculate(String person) {
		double res = 0;
		/**
		 * add your function here
		 * for example: f(x)= sin(x) x [0, 3.14] 
		 * set the genetic length is 20, so the mapping relation is
		 * [0, 2^20] -> [0, 3.14]
		 */
		double N = 20;
		//Integer.parseInt(person, 2);
		double tem = Long.parseLong(person, 2);
		double scope = Math.pow(2, person.length()) - 1;
		//double N = scope;
		double x = tem*N/scope;
		//res = Math.cos(x)+Math.sin(x);
		//double N = Math.pow(2, person.length()) -1;
		if (x > 1)
			res = -(1d/6d)*x+(7d/6d);
		else
			res = 2*x - 1;
		
		//System.out.println("tem: " + tem + " scope: " + scope + " x: " + x + " res: " + res );
		return res;
	}
	static public boolean better(double a, double b) {
		return a>b?true:false;
	}
}

class People {
	public int p_num;
	public int p_length;
	private String persons[];
	private double fitness[];
	
	public People(People people) {
		this.persons = people.persons;
		this.fitness = people.fitness;
	}
	
	public People(int num, int length) {
		p_num = num;
		p_length = length;
		fitness = new double[num];
		persons = new String[num];
				
		for(int i = 0; i < num; i++) {
			persons[i] = "";
			for(int j = 0; j < length; j++) {
				if (Math.random() > 0.5) {
					persons[i] += "0";
				} else {
					persons[i] += "1";
				}
			}
		}
		//System.out.println(persons[0]);
	}
	
	public void caculateFitness() {
		for (int i = 0; i < p_num; i++) {
			fitness[i] = Function.caculate(persons[i]);
		}
	}
	
	public int getBest() {
		int res = 0;
		for (int i = 0; i<p_num; i++) {
			if(Function.better(fitness[i],fitness[res]))
				res = i;
		}
		return res;
	}
	
	public double[] getFitness() {
		return fitness;
	}
	
	public String[] getPeople() {
		return persons;
	}
	
}

class Evolution {
	/*
	 * 
	 * @param p_s 选择算子
	 * @param p_c 交叉算子 
	 * @param p_m 变异算子
	 */
	private double ps;
	private double pc;
	private double pm;
	private People people;
	
	public Evolution(double p_s, double p_c, double p_m, People p) {
		ps = p_s;
		pc = p_c;
		pm = p_m;
		people = p;
	}
	
	/*
	 * 使用锦标赛的选择算法
	 */
	public void select() {
		for (int i = 0; i < people.p_num; i++) {
			int pos1 = (int) (Math.random()*people.p_num);
			int pos2 = (int) (Math.random()*people.p_num);
			if (Function.better(people.getFitness()[pos1], people.getFitness()[pos2]))
				people.getPeople()[i] = people.getPeople()[pos1];
			else
				people.getPeople()[i] = people.getPeople()[pos2];
			
		}
	}
	/*
	 * 交叉
	 */
	public void crossOver() {
		for (int i=0; i < (int) (pc*people.p_num); i++) {
			int pos1 = (int) (Math.random()*people.p_num);
			int pos2 = (int) (Math.random()*people.p_num);
			int cross_pos = (int) (Math.random()*people.p_length);
			
			String temp1 = people.getPeople()[pos1].substring(0,cross_pos)
			+people.getPeople()[pos2].substring(cross_pos);

			people.getPeople()[pos2] = people.getPeople()[pos2].substring(0,cross_pos)
			+people.getPeople()[pos1].substring(cross_pos);
			
			people.getPeople()[pos1] = temp1;
			
		}
	}
	
	/*
	 * 变异
	 */
	
	public void mutation() {
		//for(int i = 0; i < people.p_num; i++) {
		int i = 0;
		if(Math.random() > 0.5)
			i = 1;
			for(int j = 0; j < people.p_length; j++) {
				if (Math.random() < pm) {
					char temp[]; 
					
					if (people.getPeople()[i].charAt(j) == '0') {
						temp = people.getPeople()[i].toCharArray();
						temp[j] = '1';
						people.getPeople()[i] = new String(temp);
					} else {
						temp = people.getPeople()[i].toCharArray();
						temp[j] = '0';
						people.getPeople()[i] = new String(temp);
					}
				}
			}
		//}
	}
	
/*	public void mutation() {
		for(int i = 0; i < (int) (pm*people.p_num); i++) {
			int pos = (int) (Math.random()*people.p_num);
			int mut_pos = (int) (Math.random()*people.p_length);
			char temp[]; 
				
			if (people.getPeople()[pos].charAt(mut_pos) == '0') {
				temp = people.getPeople()[pos].toCharArray();
				temp[mut_pos] = '1';
				people.getPeople()[pos] = new String(temp);
			} else {
				temp = people.getPeople()[pos].toCharArray();
				temp[mut_pos] = '0';
				people.getPeople()[pos] = new String(temp);
			}
		}
	}*/
	
	
}

